import Vue from 'vue'
import store from '@/store/index'
import { uId } from 'dtc'
import { isEqual } from 'lodash-es'

const mouseevent = [
  'auxclick',
  'click',
  'contextmenu',
  'dblclick',
  'mousedown',
  'mouseenter',
  'mouseleave',
  'mousemove',
  'mouseover',
  'mouseout',
  'mouseup',
  'pointerlockchange',
  'pointerlockerror',
  'select',
  'wheel'
]

function findPartName(vnode) {
  if (!vnode) return []
  const context = vnode.context
  let tags = []
  const tag = vnode.componentOptions?.tag
  tag && tags.push(tag)
  if (tag !== 'anovPart') {
    tags = tags.concat(findPartName(context.$vnode))
  }
  return tags
}

Vue.directive('remote', {
  inserted: (el, binding, vnode) => {
    const { value } = binding
    if (!value) {
      console.warn('v-remote directive required binding value.')
      return
    }
    // 初始化部件/组件
    let partName, compName, outerPartName
    if (value.partName) {
      partName = value.partName
      compName = vnode.componentOptions.tag
    } else {
      let names = findPartName(vnode)
      if (names.length >= 2) {
        partName = names.slice(-2, -1)[0]
        compName = names[0]
        outerPartName = names.slice(-1)[0]
      }
    }
    if (!partName) {
      console.warn(`v-remote can't find "partName" you have to pass it.`)
      return
    }
    // 把数据放到part对象里
    let routeName
    if (outerPartName === 'anovPart') {
      routeName = vnode.context.$route.name
    } else {
      routeName = null
    }

    const id = uId(10)
    el.dataset.remote = JSON.stringify({ routeName, partName, compName, id })
    store.commit('page/ADD_REMOTE', {
      routeName,
      partName,
      compName,
      id,
      ...value
    })
    // action
    let action = {
      id,
      name: id,
      type: 'remote',
      exec: (app, param) => {
        const { event = 'change', modelKeyName } = binding.value
        const { context, componentInstance } = vnode
        if (componentInstance) {
          // vnode 是 vue component
          if (componentInstance[event]) {
            componentInstance[event](param)
          } else if (modelKeyName && modelKeyName in context) {
            // 利用 v-model 快速修改数据
            context[modelKeyName] = param
          } else {
            componentInstance?.$emit(event, param)
            console.warn(
              `[v-remote] We found "event" neither "modelKeyName" configured correctly, so we triggered the default '${event}' event you passed,
              visite https://anov.cucloud.cn/anov-dev-doc/guide/remote.html#v-remote-%E6%8C%87%E4%BB%A4 for more infomation.`
            )
          }
        } else {
          // vnode 是原生元素
          if (modelKeyName && modelKeyName in context) {
            // 利用 v-model 快速修改数据
            context[modelKeyName] = param
          } else {
            // 这种情况直接触发原生的事件
            const elm = vnode.elm
            let myEvent
            if (mouseevent.includes(event)) {
              myEvent = new MouseEvent(event, {
                cancelable: true
              })
              // 携带用户自定义数据
              myEvent.data = param
            } else {
              myEvent = new CustomEvent(event, { detail: param })
            }
            elm.dispatchEvent(myEvent)
          }
        }
      }
    }
    app.actionServer.addActions(action)
  },

  componentUpdated: (el, binding) => {
    if (isEqual(binding.oldValue, binding.value)) {
      return
    }
    let mergedValue = { ...binding.oldValue, ...binding.value }
    try {
      let dataset = JSON.parse(el.dataset.remote)
      store.commit('page/ADD_REMOTE', {
        ...dataset,
        ...mergedValue
      })
    } catch (error) {
      console.log(error)
    }
  },

  unbind: (el) => {
    try {
      let dataset = JSON.parse(el.dataset.remote)
      app.actionServer.removeActions(dataset.id)
      store.commit('page/REMOVE_REMOTE', {
        ...dataset
      })
    } catch (error) {
      console.log(error)
    }
  }
})

window.addEventListener('beforeunload', () => {
  store.commit('page/CLEAR_REMOTE')
})
